#import <stdio.h>
#import <math.h>
#import <strings.h>
#import <stdlib.h>
#import <streams/streams.h>
#import <appkit/graphics.h>
#import <appkit/NXBitmapImageRep.h>
#import "NXBitmapImageRepControl.h"
#import "ImageControl.h"
#import "pbm.h"

@implementation PBM

	NXStream		*myStream;
	unsigned char		*data;
	char				type[5];
	int				width, height;
	int				cwid;
	int				iwid;

- init
{
	return self;
}

- free
{
	return self;
}

- killToEOL
{
	while (NXGetc(myStream) != '\n') ;
	return self;
}

- getString: (char *)str from: (NXStream *)stream
{
	char		buffer[256];
	
	do {
		NXScanf(stream, "%s", str);
		if (str[0] == '#') {
			NXScanf(stream, "%[^\n]", buffer); (void)NXGetc(stream);
		}
	} while (str[0] == '#');

	return self;
}

- (int)getIntFrom: (NXStream *)stream
{
	char		buffer[256];
	
	do {
		NXScanf(stream, "%s", buffer);
		if (buffer[0] == '#') {
			NXScanf(stream, "%[^\n]", buffer); (void)NXGetc(stream);
		}
		else break;
	} while (1);
	return(atoi(buffer));
}

- (BOOL)readRawFromStream
{
	int				x, shift, curByte;
	unsigned int		c;

#ifdef DEBUG
	fprintf(stderr, "Okay, we're off and reading raw data\n");
#endif

	shift = 7;
	data[curByte = 0] = 0;
	for (x = 0; x < width * height; x++) {
		c = [self getIntFrom: myStream];
//		NXScanf(myStream, "%d", &c);
//		fprintf(stderr, "%c:", c);
		if (NXAtEOS(myStream)) return NO;
		data[curByte] |= (c << shift);
		if (!(shift--)) {
			shift = 7;
			data[++curByte] = 0;
		}
	}

	return YES;
}

- (BOOL)readCompressedFromStream
{
#ifdef DEBUG
	fprintf(stderr, "Okay, we're off and reading condensed data\n");
#endif

	[self killToEOL];

	if (NXRead(myStream, data, sizeof(unsigned char) * ((width * height) / 8)) != ((width * height) / 8)) return NO;

	return YES;
}

- readFromStream: (NXStream *)stream from: sender;
{
	id		image;

#ifdef DEBUG
	fprintf(stderr, "Made it to read\n");
#endif

	myStream = stream;

	[self getString: type from: myStream];
	width = [self getIntFrom: myStream];
	height = [self getIntFrom: myStream];
//	NXScanf(myStream, "%s %d %d", type, &width, &height);
	cwid = sizeof(unsigned char) * 8;
	iwid = sizeof(unsigned int) * 8;
#ifdef DEBUG
	fprintf(stderr, "Type %s of dimensions %dx%d\n", type, width, height);
#endif

	image = [[NXBitmapImageRep alloc] 	initData: NULL
										pixelsWide: width
										pixelsHigh: height
										bitsPerSample: 1
										samplesPerPixel: 1
										hasAlpha: NO
										isPlanar: NO
										colorSpace: NX_OneIsBlackColorSpace
										bytesPerRow: 0
										bitsPerPixel: 0];
	if (!image) return nil;
	data = [image data]; 

	if (!strcmp(type, "P1")) {
		if (![self readRawFromStream]) {
			[image free];
			return nil;
		}
	}
	else if (!strcmp(type, "P4")) {
		if (![self readCompressedFromStream]) {
			[image free];
			return nil;
		}
	}
	else return nil;
	
	return image;
}

- (BOOL)write: (id)image toStream: (NXStream *)stream from: sender;
{
	id				newImage;
	id				imageCon;
	unsigned char		*dataPtr;
	int				size, x;
	
	imageCon = [sender getImageControl: image];
#ifdef DEBUG
	fprintf(stderr, "1...");
#endif
	newImage = [imageCon ditherImage];
#ifdef DEBUG
	fprintf(stderr, "2...");
#endif
	[imageCon free];
#ifdef DEBUG
	fprintf(stderr, "3...");
#endif
	imageCon = [sender getImageControl: image];
#ifdef DEBUG
	fprintf(stderr, "4...\n");
#endif
	
	NXPrintf(stream, "P4\n");
	NXPrintf(stream, "%d %d\n", [newImage pixelsWide], [newImage pixelsHigh]);
	size = [newImage pixelsWide] * [newImage pixelsHigh] / 8;
#ifdef DEBUG
	fprintf(stderr, "%d\n", size);
#endif
	for (x = 0, dataPtr = [newImage data]; x < size; x++) {
		NXPutc(stream, *dataPtr++);
	}
	
	[newImage free];
	
	return YES;
}

- readAllFromStream: (NXStream *)stream from: sender
{
	return nil;
}

- (BOOL)writeAll: (id)image toStream: (NXStream *)stream
{
	return NO;
}

- customSaveView: (int)width
{
	return nil;
}

- customOpenView: (int)width
{
	return nil;
}

- (char *)getFormatName
{
	return("Portable Bitmap (PBM)");
}

 - (BOOL)setCustomParameter: (const char *)parameter withValue: (void *)ptr
{
	return NO;
}

 - (void *)getCustomParameter: (const char *)parameter
{
	return nil;
}

- (char *)copyrightNotice
{
	return "PBM Converter\nby Alex Raftis\nCopyright (c) 1991 Cal Poly State University\nEmail bugs to alex@data.ACS.CalPoly.EDU";
}
 
- (int)errorState
{
	return CONVERT_ERR_NONE;
}
 
- (int)errorMessage
{
	return ERROR_NO_ERROR;
}

- (char *)errorStringMessage
{
	return NULL;
}
 
- (BOOL)needsWindowServer;
{
	return NO;
}

- (char *)protocolVersion
{
	return "1.0";
}

@end
